/*-
 * Copyright (c) <2010-2019>, Intel Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
/* Created 2010 by Keith Wiles @ intel.com */

#ifndef _PKTGEN_PORT_CFG_H_
#define _PKTGEN_PORT_CFG_H_

#include <stdio.h>
#include <string.h>
#include <rte_version.h>
#include <rte_atomic.h>
#include <rte_spinlock.h>
#include <rte_pci.h>

#undef BPF_MAJOR_VERSION
#include <pcap/pcap.h>

#include "pktgen-seq.h"
#include "pktgen-range.h"
#include "pktgen-stats.h"
#include "pktgen-pcap.h"
#include "pktgen-dump.h"
#include "pktgen-ether.h"

#ifdef __cplusplus
extern "C" {
#endif

#define MAX_PORT_DESC_SIZE  132
#define USER_PATTERN_SIZE   16

typedef struct port_sizes_s {
	uint64_t _64;		/**< Number of 64 byte packets */
	uint64_t _65_127;	/**< Number of 65-127 byte packets */
	uint64_t _128_255;	/**< Number of 128-255 byte packets */
	uint64_t _256_511;	/**< Number of 256-511 byte packets */
	uint64_t _512_1023;	/**< Number of 512-1023 byte packets */
	uint64_t _1024_1518;	/**< Number of 1024-1518 byte packets */
	uint64_t broadcast;	/**< Number of broadcast packets */
	uint64_t multicast;	/**< Number of multicast packets */
	uint64_t jumbo;		/**< Number of Jumbo frames */
	uint64_t runt;		/**< Number of Runt frames */
	uint64_t unknown;	/**< Number of unknown sizes */
} port_sizes_t;

struct mbuf_table {
	uint16_t len;
	struct rte_mbuf *m_table[DEFAULT_PKT_BURST];
};

enum {						/* Per port flag bits */
	/* Supported packet modes non-exclusive */
	SEND_ARP_REQUEST        = (1 <<  0),	/**< Send a ARP request */
	SEND_GRATUITOUS_ARP     = (1 <<  1),	/**< Send a Gratuitous ARP */
	ICMP_ECHO_ENABLE_FLAG   = (1 <<  2),	/**< Enable ICMP Echo support */
	BONDING_TX_PACKETS      = (1 <<  3),	/**< Bonding driver send zero pkts */

	PROCESS_INPUT_PKTS      = (1 <<  4),	/**< Process input packets */
	CAPTURE_PKTS            = (1 <<  5),	/**< Capture received packets */
	SEND_PING4_REQUEST      = (1 <<  6),	/**< Send a IPv4 Ping request */
	SEND_PING6_REQUEST      = (1 <<  7),	/**< Send a IPv6 Ping request */

	PROCESS_RX_TAP_PKTS     = (1 <<  8),	/**< Handle RX TAP interface packets */
	PROCESS_TX_TAP_PKTS     = (1 <<  9),	/**< Handle TX TAP interface packets */
	PROCESS_GARP_PKTS       = (1 << 10),	/**< Process GARP packets and update the dst MAC address */

	/* Exclusive Packet sending modes */
	SEND_PCAP_PKTS          = (1 << 12),	/**< Send a pcap file of packets */
	SEND_RANGE_PKTS         = (1 << 13),	/**< Send a range of packets */
	SEND_SEQ_PKTS           = (1 << 14),	/**< Send a sequence of packets */
	SEND_LATENCY_PKTS       = (1 << 15),	/**< Send latency packets */

	SEND_RATE_PACKETS       = (1 << 16),	/**< Send rate pacing packets */
	SEND_RANDOM_PKTS        = (1 << 17),	/**< Send random bitfields in packets */

	/* Exclusive Packet type modes */
	SEND_VLAN_ID            = (1 << 20),	/**< Send packets with VLAN ID */
	SEND_MPLS_LABEL         = (1 << 21),	/**< Send MPLS label */
	SEND_Q_IN_Q_IDS         = (1 << 22),	/**< Send packets with Q-in-Q */
	SEND_GRE_IPv4_HEADER    = (1 << 23),	/**< Encapsulate IPv4 in GRE */

	SEND_GRE_ETHER_HEADER   = (1 << 24),	/**< Encapsulate Ethernet frame in GRE */
	SEND_VXLAN_PACKETS      = (1 << 25),	/**< Send VxLAN Packets */

	/* Sending flags */
	SENDING_PACKETS         = (1 << 30),	/**< sending packets on this port */
	SEND_FOREVER            = (1 << 31),	/**< Send packets forever */

	SEND_ARP_PING_REQUESTS  =
		(SEND_ARP_REQUEST | SEND_GRATUITOUS_ARP | SEND_PING4_REQUEST |
		 SEND_PING6_REQUEST)
};

#define EXCLUSIVE_MODES		( \
	SEND_PCAP_PKTS | \
	SEND_RANGE_PKTS | \
	SEND_SEQ_PKTS | \
	SEND_RANDOM_PKTS | \
	SEND_LATENCY_PKTS | \
	SEND_RATE_PACKETS )

#define EXCLUSIVE_PKT_MODES ( \
	SEND_VLAN_ID | \
	SEND_VXLAN_PACKETS | \
	SEND_MPLS_LABEL | \
	SEND_Q_IN_Q_IDS | \
	SEND_GRE_IPv4_HEADER | \
	SEND_GRE_ETHER_HEADER )

#define RTE_PMD_PARAM_UNSET -1

/*
 * Configurable values of RX and TX ring threshold registers.
 */
typedef struct ring_conf_s {
	int8_t rx_pthresh;
	int8_t rx_hthresh;
	int8_t rx_wthresh;

	int8_t tx_pthresh;
	int8_t tx_hthresh;
	int8_t tx_wthresh;

	/*
	 * Configurable value of RX free threshold.
	 */
	int16_t rx_free_thresh;

	/*
	 * Configurable value of RX drop enable.
	 */
	int8_t rx_drop_en;

	/*
	 * Configurable value of TX free threshold.
	 */
	int16_t tx_free_thresh;

	/*
	 * Configurable value of TX RS bit threshold.
	 */
	int16_t tx_rs_thresh;

#if RTE_VERSION <= RTE_VERSION_NUM(18, 5, 0, 0)
	/*
	 * Configurable value of TX queue flags.
	 */
	int32_t txq_flags;
#endif

	/*
	 * Receive Side Scaling (RSS) configuration.
	 */
	uint64_t rss_hf;
} ring_conf_t;

typedef enum {
	ZERO_FILL_PATTERN = 1,
	ABC_FILL_PATTERN,
	USER_FILL_PATTERN,
	NO_FILL_PATTERN,
} fill_t;

typedef void (*tx_func_t)(struct port_info_s *info, uint16_t qid);

typedef struct {
	uint16_t	fps;
	uint16_t	vlines;
	uint16_t    pixels;
	uint16_t	color_bits;
	uint16_t	payload;
	uint16_t	overhead;
	uint32_t	pad0;

	uint32_t    bytes_per_vframe;
	uint32_t    bits_per_sec;
	uint32_t	pkts_per_vframe;		/* bytes_per_vframe/payload */
	uint32_t	total_pkts_per_sec;		/* pkts_per_vframe * fps */

	double		pps_rate;

	uint64_t	curr_tsc;
	uint64_t	cycles_per_pkt;
	uint64_t	next_tsc;
} rate_info_t;

typedef struct port_info_s {
	uint16_t pid;		/**< Port ID value */
	uint16_t tx_burst;	/**< Number of TX burst packets */
	uint16_t lsc_enabled;
	uint16_t pad0;
	double tx_rate;		/**< Percentage rate for tx packets with fractions */
	rte_atomic32_t port_flags;	/**< Special send flags for ARP and other */

	rte_atomic64_t transmit_count;	/**< Packets to transmit loaded into current_tx_count */
	rte_atomic64_t current_tx_count;/**< Current number of packets to send */
	uint64_t tx_cycles;	/**< Number cycles between TX bursts */
	uint64_t tx_pps;	/**< Transmit packets per seconds */
	uint64_t delta;		/**< Delta value for latency testing */
	uint64_t tx_count;	/**< Total count of tx attempts */

	/* Packet buffer space for traffic generator, shared for all packets per port */
	uint16_t seqIdx;	/**< Current Packet sequence index 0 to NUM_SEQ_PKTS */
	uint16_t seqCnt;	/**< Current packet sequence max count */
	uint16_t prime_cnt;	/**< Set the number of packets to send in a prime command */
	uint16_t vlanid;	/**< Set the port VLAN ID value */
	uint8_t cos;		/**< Set the port 802.1p cos value */
	uint8_t tos;		/**< Set the port tos value */
	rte_spinlock_t port_lock;/**< Used to sync up packet constructor between cores */
	pkt_seq_t *seq_pkt;	/**< Sequence of packets seq_pkt[NUM_SEQ_PKTS]=default packet */
	range_info_t range;	/**< Range Information */

	uint32_t mpls_entry;	/**< Set the port MPLS entry */
	uint32_t gre_key;	/**< GRE key if used */

	uint16_t nb_mbufs;	/**< Number of mbufs in the system */
	uint64_t max_avg_latency;	/**< TX Latency sequence */
	uint64_t avg_latency;	/**< Latency delta in clock ticks */
	uint64_t min_avg_latency;	/**< RX Latency sequence */

	rate_info_t rate;

	RTE_STD_C11
	union {
		uint64_t vxlan;		/**< VxLAN 64 bit word */
		struct {
			uint16_t vni_flags;	/**< VxLAN Flags */
			uint16_t group_id;	/**< VxLAN Group Policy ID */
			uint32_t vxlan_id;	/**< VxLAN VNI */
		};
	};

	uint32_t magic_errors;
	uint32_t latency_nb_pkts;
	uint64_t jitter_threshold;
	uint64_t jitter_threshold_clks;
	uint64_t jitter_count;
	uint64_t prev_latency;
	uint64_t max_latency;

	pkt_stats_t stats;	/**< Statistics for a number of stats */
	port_sizes_t sizes;	/**< Stats for the different packets sizes */

	eth_stats_t curr_stats;	/**< current port statistics */
	eth_stats_t prev_stats;	/**< previous port statistics */
	eth_stats_t rate_stats;	/**< current packet rate statistics */
	eth_stats_t base_stats;	/**< base port statistics */
	uint64_t max_ipackets;	/**< Max seen input packet rate */
	uint64_t max_opackets;	/**< Max seen output packet rate */
	uint64_t max_missed;	/**< Max missed packets seen */
	struct qstats_s {
		uint64_t rxpkts;
		uint64_t txpkts;
		uint64_t rxbytes;
		uint64_t txbytes;
	} qstats[NUM_Q];

	struct rte_eth_link link;	/**< Link Information like speed and duplex */

	struct q_info {
		rte_atomic32_t flags;		/**< Special send flags for ARP and other */
		struct mbuf_table tx_mbufs;	/**< mbuf holder for transmit packets */
		struct rte_mempool *rx_mp;	/**< Pool pointer for port RX mbufs */
		struct rte_mempool *tx_mp;	/**< Pool pointer for default TX mbufs */
		struct rte_mempool *rate_mp;	/**< Pool pointer for port Rate TX mbufs */
		struct rte_mempool *range_mp;	/**< Pool pointer for port Range TX mbufs */
		struct rte_mempool *seq_mp;	/**< Pool pointer for port Sequence TX mbufs */
		struct rte_mempool *pcap_mp;	/**< Pool pointer for port PCAP TX mbufs */
		struct rte_mempool *special_mp;	/**< Pool pointer for special TX mbufs */
	} q[NUM_Q];

	int32_t rx_tapfd;	/**< Rx Tap file descriptor */
	int32_t tx_tapfd;	/**< Tx Tap file descriptor */
	pcap_info_t *pcap;	/**< PCAP information header */
	pcap_info_t *pcaps[NUM_Q];	/**< Per Tx queue PCAP information headers */
	uint64_t pcap_cycles;	/**< number of cycles for pcap sending */

	int32_t pcap_result;	/**< PCAP result of filter compile */
	struct bpf_program pcap_program;/**< PCAP filter program structure */

	/* Packet dump related */
	struct packet {
		void *data;	/**< Packet data */
		uint32_t len;	/**< Length of data */
	} dump_list[MAX_DUMP_PACKETS];
	uint8_t dump_head;	/**< Index of last packet written to screen */
	uint8_t dump_tail;	/**< Index of last valid packet in dump_list */
	uint8_t dump_count;	/**< Number of packets the user requested */

	struct rnd_bits_s     *rnd_bitfields;	/**< Random bitfield settings */

	struct rte_eth_dev_info dev_info;	/**< PCI info + driver name */
	char user_pattern[USER_PATTERN_SIZE];	/**< User set pattern values */
	fill_t fill_pattern_type;		/**< Type of pattern to fill with */
} port_info_t;

struct vxlan {
	uint16_t vni_flags;	/**< VxLAN Flags */
	uint16_t group_id;	/**< VxLAN Group Policy ID */
	uint32_t vxlan_id;	/**< VxLAN VNI */
};

void pktgen_config_ports(void);

/**
 * Atomically subtract a 64-bit value from the tx counter.
 *
 * @param v
 *   A pointer to the atomic tx counter.
 * @param burst
 *   The value to be subtracted from the counter for tx burst size.
 * @return
 *   The number of packets to burst out
 */
static inline uint64_t
pkt_atomic64_tx_count(rte_atomic64_t *v, int64_t burst)
{
	int success;
	int64_t tmp2;

	do {
		int64_t tmp1 = v->cnt;

		if (tmp1 == 0)
			return 0;
		tmp2 = likely(tmp1 > burst) ? burst : tmp1;
		success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
					      tmp1,
					      tmp1 - tmp2);
	} while (success == 0);

	return tmp2;
}

static inline void
rte_eth_rxconf_dump(FILE *f, struct rte_eth_rxconf *rx)
{
	fprintf(f, "  RX Conf:\n");
	fprintf(f,
		"     pthresh        :%5" PRIu16 " hthresh          :%5" PRIu16 " wthresh        :%5" PRIu16 "\n",
		rx->rx_thresh.pthresh,
		rx->rx_thresh.hthresh,
		rx->rx_thresh.wthresh);
	fprintf(f,
		"     Free Thresh    :%5" PRIu16 " Drop Enable      :%5" PRIu16 " Deferred Start :%5" PRIu16 "\n",
		rx->rx_free_thresh,
		rx->rx_drop_en,
		rx->rx_deferred_start);
	fprintf(f,
		"     offloads       :%016" PRIx64 "\n",
		rx->offloads);
}

static inline void
rte_eth_txconf_dump(FILE *f, struct rte_eth_txconf *tx)
{
	fprintf(f, "  TX Conf:\n");
	fprintf(f,
		"     pthresh        :%5" PRIu16 " hthresh          :%5" PRIu16 " wthresh        :%5" PRIu16 "\n",
		tx->tx_thresh.pthresh,
		tx->tx_thresh.hthresh,
		tx->tx_thresh.wthresh);
#if RTE_VERSION <= RTE_VERSION_NUM(18, 5, 0, 0)
	fprintf(f,
		"     Free Thresh    :%5" PRIu16 " RS Thresh        :%5" PRIu16 " Deferred Start :%5" PRIu16 "  TXQ Flags: %08x\n",
		tx->tx_free_thresh,
		tx->tx_rs_thresh,
		tx->tx_deferred_start,
		tx->txq_flags);
#else
	fprintf(f,
		"     Free Thresh    :%5" PRIu16 " RS Thresh        :%5" PRIu16 " Deferred Start :%5" PRIu16 "\n",
		tx->tx_free_thresh,
		tx->tx_rs_thresh,
		tx->tx_deferred_start);
#endif
	fprintf(f,
		"     offloads       :%016" PRIx64 "\n",
		tx->offloads);
}

static inline void
rte_eth_desc_lim_dump(FILE *f, struct rte_eth_desc_lim *lim, int tx_flag)
{
	fprintf(f, "  %s: descriptor Limits\n", tx_flag ? "Tx" : "Rx");

	fprintf(f,
		"     nb_max         :%5" PRIu16 "  nb_min          :%5" PRIu16 "  nb_align      :%5" PRIu16 "\n",
		lim->nb_max, lim->nb_min, lim->nb_align);
	fprintf(f,
		"     nb_seg_max     :%5" PRIu16 "  nb_mtu_seg_max  :%5" PRIu16 "\n",
		lim->nb_seg_max, lim->nb_mtu_seg_max);
}

#if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0)
static inline void
rte_eth_dev_portconf_dump(FILE *f, struct rte_eth_dev_portconf *conf, int tx_flag)
{
	fprintf(f, "  %s: Port Config\n", tx_flag ? "Tx" : "Rx");

	fprintf(f,
		"     burst_size     :%5" PRIu16 "  ring_size       :%5" PRIu16 "  nb_queues     :%5" PRIu16 "\n",
		conf->burst_size, conf->ring_size, conf->nb_queues);
}
#endif

#if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0)
static inline void
rte_eth_switch_info_dump(FILE *f, struct rte_eth_switch_info *sw)
{
	fprintf(f, "  Switch Info: %s\n", sw->name);

	fprintf(f,
		"     domain_id      :%5" PRIu16 "  port_id         :%5" PRIu16 "\n",
		sw->domain_id, sw->port_id);
}
#endif

static inline int
rte_get_rx_capa_list(uint64_t rx_capa, char *buf, size_t len)
{
	uint32_t i;
	int ret;
#define _(x)	#x
	struct {
		uint64_t flag;
		const char *name;
	} rx_flags[] = {
	{ DEV_RX_OFFLOAD_VLAN_STRIP,		_(VLAN_STRIP) },
	{ DEV_RX_OFFLOAD_IPV4_CKSUM,		_(IPV4_CKSUM) },
	{ DEV_RX_OFFLOAD_UDP_CKSUM,		_(UDP_CKSUM) },
	{ DEV_RX_OFFLOAD_TCP_CKSUM,		_(TCP_CKSUM) },
	{ DEV_RX_OFFLOAD_TCP_LRO,		_(TCP_LRO) },
	{ DEV_RX_OFFLOAD_QINQ_STRIP,		_(QINQ_STRIP) },
	{ DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM,	_(OUTER_IPV4_CKSUM) },
	{ DEV_RX_OFFLOAD_MACSEC_STRIP,		_(MACSEC_STRIP) },
	{ DEV_RX_OFFLOAD_HEADER_SPLIT,		_(HEADER_SPLIT) },
	{ DEV_RX_OFFLOAD_VLAN_FILTER,		_(VLAN_FILTER) },
	{ DEV_RX_OFFLOAD_VLAN_EXTEND,		_(VLAN_EXTEND) },
	{ DEV_RX_OFFLOAD_JUMBO_FRAME,		_(JUMBO_FRAME) },
	{ DEV_RX_OFFLOAD_SCATTER,		_(SCATTER) },
	{ DEV_RX_OFFLOAD_TIMESTAMP,		_(TIMESTAMP) },
	{ DEV_RX_OFFLOAD_SECURITY,		_(SECURITY) },
#if RTE_VERSION < RTE_VERSION_NUM(18,11,0,0)
	{ DEV_RX_OFFLOAD_CRC_STRIP,		_(KEEP_CRC) }
#else
	{ DEV_RX_OFFLOAD_KEEP_CRC,		_(KEEP_CRC) },
	{ DEV_RX_OFFLOAD_SCTP_CKSUM,		_(SCTP_CKSUM) },
	{ DEV_RX_OFFLOAD_OUTER_UDP_CKSUM, 	_(OUTER_UDP_CKSUM) }
#endif
	};
#undef _

	if (len == 0)
		return -1;

	buf[0] = '\0';
	for(i = 0; i < RTE_DIM(rx_flags); i++) {
		if ((rx_capa & rx_flags[i].flag) != rx_flags[i].flag)
		continue;

		ret = snprintf(buf, len, "%s ", rx_flags[i].name);
		if (ret < 0)
			return -1;
		if ((size_t)ret >= len)
			return -1;
		buf += ret;
		len -= ret;
	}
	return 0;
}

static inline int
rte_get_tx_capa_list(uint64_t tx_capa, char *buf, size_t len)
{
	uint32_t i;
	int ret;
#define _(x)	#x
	struct {
		uint64_t flag;
		const char *name;
	} tx_flags[] = {
	{ DEV_TX_OFFLOAD_VLAN_INSERT,		_(VLAN_INSERT) },
	{ DEV_TX_OFFLOAD_IPV4_CKSUM, 		_(IPV4_CKSUM) },
	{ DEV_TX_OFFLOAD_UDP_CKSUM, 		_(UDP_CKSUM) },
	{ DEV_TX_OFFLOAD_TCP_CKSUM, 		_(TCP_CKSUM) },
	{ DEV_TX_OFFLOAD_SCTP_CKSUM, 		_(SCTP_CKSUM) },
	{ DEV_TX_OFFLOAD_TCP_TSO, 		_(TCP_TSO) },
	{ DEV_TX_OFFLOAD_UDP_TSO, 		_(UDP_TSO) },
	{ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM,	_(OUTER_IPV4_CKSUM) },
	{ DEV_TX_OFFLOAD_QINQ_INSERT, 		_(QINQ_INSERT) },
	{ DEV_TX_OFFLOAD_VXLAN_TNL_TSO, 	_(VXLAN_TNL_TSO) },
	{ DEV_TX_OFFLOAD_GRE_TNL_TSO, 		_(GRE_TNL_TSO) },
	{ DEV_TX_OFFLOAD_IPIP_TNL_TSO, 		_(IPIP_TNL_TSO) },
	{ DEV_TX_OFFLOAD_GENEVE_TNL_TSO, 	_(GENEVE_TNL_TSO) },
	{ DEV_TX_OFFLOAD_MACSEC_INSERT, 	_(MACSEC_INSERT) },
	{ DEV_TX_OFFLOAD_MT_LOCKFREE, 		_(MT_LOCKFREE) },
	{ DEV_TX_OFFLOAD_MULTI_SEGS, 		_(MULTI_SEGS) },
	{ DEV_TX_OFFLOAD_MBUF_FAST_FREE,	_(MBUF_FAST_FREE) },
	{ DEV_TX_OFFLOAD_SECURITY, 		_(SECURITY) },
#if RTE_VERSION >= RTE_VERSION_NUM(18,11,0,0)
	{ DEV_TX_OFFLOAD_UDP_TNL_TSO, 		_(UDP_TNL_TSO) },
	{ DEV_TX_OFFLOAD_IP_TNL_TSO, 		_(IP_TNL_TSO) },
	{ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM,	_(OUTER_UDP_CKSUM) },

#if RTE_VERSION < RTE_VERSION_NUM(19,11,0,0)
	{ DEV_TX_OFFLOAD_MATCH_METADATA,	_(MATCH_METADATA) },
#endif
#endif
	};
#undef _

	if (len == 0)
		return -1;

	buf[0] = '\0';
	for(i = 0; i < RTE_DIM(tx_flags); i++) {
		if ((tx_capa & tx_flags[i].flag) != tx_flags[i].flag)
		continue;

		ret = snprintf(buf, len, "%s ", tx_flags[i].name);
		if (ret < 0)
			return -1;
		if ((size_t)ret >= len)
			return -1;
		buf += ret;
		len -= ret;
	}
	return 0;
}

static inline void
rte_eth_dev_info_dump(FILE *f, uint16_t pid)
{
	struct rte_eth_dev_info dev_info;
	struct rte_eth_dev_info *di = &dev_info;
	char buf[512];

	rte_eth_dev_info_get(pid, &dev_info);

	if (!f)
		f = stderr;

#if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0)
	fprintf(f, "** Device Info (%s, if_index:%" PRId32 ", flags %08" PRIu32 ") **\n",
		rte_eth_devices[pid].data->name, di->if_index, *di->dev_flags);
#else
	fprintf(f, "** Device Info (%s, if_index:%" PRId32 ") **\n",
		rte_eth_devices[pid].data->name, di->if_index);
#endif

	fprintf(f,
		"   min_rx_bufsize :%5" PRIu32 "  max_rx_pktlen     :%5" PRIu32 "  hash_key_size :%5" PRIu8 "\n",
		di->min_rx_bufsize, di->max_rx_pktlen, di->hash_key_size);
	fprintf(f,
		"   max_rx_queues  :%5" PRIu16 "  max_tx_queues     :%5" PRIu16 "  max_vfs       :%5" PRIu16 "\n",
		di->max_rx_queues, di->max_tx_queues, di->max_vfs);
	fprintf(f,
		"   max_mac_addrs  :%5" PRIu32 "  max_hash_mac_addrs:%5" PRIu32 "  max_vmdq_pools:%5" PRIu16 "\n",
		di->max_mac_addrs, di->max_hash_mac_addrs, di->max_vmdq_pools);
	fprintf(f,
		"   vmdq_queue_base:%5" PRIu16 "  vmdq_queue_num    :%5" PRIu16 "  vmdq_pool_base:%5" PRIu16 "\n",
		di->vmdq_queue_base, di->vmdq_queue_num, di->vmdq_pool_base);
	fprintf(f,
		"   nb_rx_queues   :%5" PRIu16 "  nb_tx_queues      :%5" PRIu16 "  speed_capa    : %08" PRIx32 "\n",
		di->nb_rx_queues, di->nb_tx_queues, di->speed_capa);
	fprintf(f, "\n");
	fprintf(f,
		"   flow_type_rss_offloads:%016" PRIx64 "  reta_size             :%5" PRIu16 "\n",
		di->flow_type_rss_offloads, di->reta_size);
	rte_get_rx_capa_list(di->rx_offload_capa, buf, sizeof(buf));
	fprintf(f,
		"   rx_offload_capa       :%s\n", buf);
	rte_get_tx_capa_list(di->tx_offload_capa, buf, sizeof(buf));
	fprintf(f,
		"   tx_offload_capa       :%s\n", buf);
	fprintf(f,
		"   rx_queue_offload_capa :%016" PRIx64,
		di->rx_queue_offload_capa);
	fprintf(f,
		"  tx_queue_offload_capa :%016" PRIx64 "\n",
		di->tx_queue_offload_capa);
#if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0)
	fprintf(f,
		"   dev_capa              :%016" PRIx64 "\n",
		di->dev_capa);
#endif
	fprintf(f, "\n");

	rte_eth_rxconf_dump(f, &di->default_rxconf);
	rte_eth_txconf_dump(f, &di->default_txconf);

	rte_eth_desc_lim_dump(f, &di->rx_desc_lim, 0);
	rte_eth_desc_lim_dump(f, &di->tx_desc_lim, 1);

#if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0)
	rte_eth_dev_portconf_dump(f, &di->default_rxportconf, 0);
	rte_eth_dev_portconf_dump(f, &di->default_txportconf, 1);

	rte_eth_switch_info_dump(f, &di->switch_info);
#endif
	fprintf(f, "\n");
}

void pktgen_set_hw_strip_crc(uint8_t val);
int pktgen_get_hw_strip_crc(void);

#ifdef __cplusplus
}
#endif

#endif  /* _PKTGEN_PORT_CFG_H_ */
